CloudFrontの署名付きCookieでプライベートコンテンツの配信
署名付きCookieはCloudFrontで配信するコンテンツをプライベートなコンテンツとして配信するための機能です。よく似た機能で署名付きURLもあります。今回は署名付きCookieでコンテンツの制限とアクセス検証します。
- 信頼されたキーグループのキーペアの作成
- CloudFront + S3でコンテンツの配信準備
- コンテンツを署名付きCookieで制限しプライベートコンテンツとして配信
CloudFrontの署名付きCookieを使ってプライベートコンテンツの配信を試します。以前はrootユーザでCloudFrontのキーペアを作成していました。現在は非推奨であり、通常のIAMユーザでCloudFrontのキーペアを作成する方法が推奨されています。ということで、推奨方法でキーペアを作成するところからはじめます。
署名付きCookie
信頼されたキーグループのキーペアの作成
署名者のキーペア作成
下記ドキュメントを参考にすすめます。
署名付き URL と署名付き Cookie を作成できる署名者の指定 - Amazon CloudFront
ローカル端末でキーペア作成。
$ openssl genrsa -out private_key.pem 2048 $ openssl rsa -pubout -in private_key.pem -out public_key.pem
公開鍵と秘密鍵のキーペアが作成されました。
$ ll total 16 -rw-r--r-- 1 ohmura.yasutaka staff 1.6K 1 15 22:04 private_key.pem -rw-r--r-- 1 ohmura.yasutaka staff 451B 1 15 22:04 public_key.pem
公開鍵のアップロード
CloudFrontを開きます。
Add public key
をクリック
任意のKey name
を設定。Key value
はpublic_key.pem
の内容をコピペ。
登録されました。ここのID
は後半の署名付きCookie作成時必要になります。後で使うためIDを控えておくかPublic keys
画面で確認できることを覚えておいてください。
CloudFront + S3でコンテンツの配信準備
S3バケット作成
配信したいファイルは網走市のPR素材をアップロード。4.4MBのPDFファイルです。
CloudFrontで配信までの流れは下記を参考。S3バケット直アクセスからオブジェクト参照のテストはしないため、S3バケットはパブリックアクセスをすべてブロックにしています。
独自ドメインのCloudFrontでPDFを配信できるようになりました。
署名付きCookieで制限
下記記事を参考にすすめていきます。
CloudFrontから対象のDestributionを選択し、BehaviorsタブからCreate Behaviorをクリック。
Path Patternは.pdf
のファイルを対象に設定してみます。
Path Patternの書式は下記サイトを参考にしてください。
ディストリビューションを作成または更新する場合に指定する値 - Amazon CloudFront
Restrict Viewer Access
をYes
に変更。推奨のTrusted Key Groups
を使いますがキーグループ未作成なのでここから作成します。
Key group name
を入力。Public keys
に準備作業で作成した公開鍵を選択しAdd
をクリックすると下の欄に表示されます。
CloudFrontの設定画面に戻ります。キーグループを作成したので更新ボタンを押し、キーグループ名を確認。Add
をクリックすると下の欄に表示されます。
独自ドメインのCloudFrontで配信していたPDFファイルがMissingKey
のエラーで見れなくなりました。
比較のためS3バケットに.jpg
の画像をアップロードしました。こちらは.pdf
ファイルではないので表示されます。
署名付きCookieでアクセス
ポリシーを複数のオブジェクトへの使用するためカスタムポリシーを作成
カスタムポリシーを使用する署名付き Cookie の設定 - Amazon CloudFront
DateLessThan
は有効期限の設定です。EpocTimeは下記サイトで変換し24時間後の値を設定しました。
Unixtime相互変換ツール | konisimple tool
{ "Statement": [ { "Resource":"https://test.[your.domain]/*", "Condition": { "DateLessThan": { "AWS:EpochTime":1610808495 } } } ] }
インデント、改行を削除する必要があります。下記サイトを利用してサクッと整形しpolicy.json
として保存しました。
改行・空白・タブ削除ツール|ちょっと便利なツール・ジェネレーター置き場
{"Statement":[{"Resource":"https://test.[your.domain]/*","Condition":{"DateLessThan":{"AWS:EpochTime":1610808495}}}]}
これからBase64 エンコードした文字列と署名された Base64 エンコードした文字列を生成します。この生成した文字列をCookieにセットして利用します。
必要なファイル
- カスタムポリシーの保存した
policy.json
ファイル - 署名者のキーペアで作成した秘密鍵の
private_key.pem
ファイル
- Base64 エンコードしたポリシー
$ cat policy.json | openssl base64 | tr '+=/' '-_~' eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly90ZXN0LmFiYXNoaXJp LmNpdHkvKiIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2No VGltZSI6MTYxMDgwODQ5NX19fV19Cg__
-
署名された Base64 エンコードしたポリシー
$ cat policy.json | openssl sha1 -sign private_key.pem | openssl base64 | tr '+=/' '-_~' 4s0aPb9BgVH91kDlJPeEnmepd4fIv5zJ45qWis9ng5joUcn4gf4H~NQL9-btqpq1 OxHqSTV4gVAa6E9mjSpeZRc12YJtPM~HoHZL4Xwee6uG7qEeYF3bWoUoyyV-Ng2K kSh8SAKmni8OHJt1Tpj-KEyfLrKxXDCTLcmDvkw~h9vrQL5MBxpDirXQYSjNJ6nE pr2EyweNQe89t4vFmBP3b6wOdfYrG1N3RE1o3MgozslXyoa2aqkr5j2xGWti8ZEC goljz-ytem5Kb45mncZC10ugRT7mJuRujt~FDnKZC~12hTKZv-haMGfZUVZZLceo VSP2I2mz6euO5HT6o9awlA__
署名付きCookieでアクセス
- CloudFront-Policy : 1.Base64 エンコードしたポリシーの文字列
- CloudFront-Signature : 2.署名された Base64 エンコードしたポリシーの文字列
- CloudFront-Key-Pair-Id : 署名者のキーペアで作成した公開鍵をマネージドコンソールから登録したときのID
対象がPDFファイルなので--output
オプションで保存します。
curl -H 'Cookie:CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly90ZXN0LmFiYXNoaXJpLmNpdHkvKiIsIkNvbmRpdGlvbiI6eyJEYXRlTGVzc1RoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTYxMDgwODQ5NX19fV19Cg__;CloudFront-Signature=4s0aPb9BgVH91kDlJPeEnmepd4fIv5zJ45qWis9ng5joUcn4gf4H~NQL9-btqpq1OxHqSTV4gVAa6E9mjSpeZRc12YJtPM~HoHZL4Xwee6uG7qEeYF3bWoUoyyV-Ng2KkSh8SAKmni8OHJt1Tpj-KEyfLrKxXDCTLcmDvkw~h9vrQL5MBxpDirXQYSjNJ6nEpr2EyweNQe89t4vFmBP3b6wOdfYrG1N3RE1o3MgozslXyoa2aqkr5j2xGWti8ZECgoljz-ytem5Kb45mncZC10ugRT7mJuRujt~FDnKZC~12hTKZv-haMGfZUVZZLceoVSP2I2mz6euO5HT6o9awlA__; CloudFront-Key-Pair-Id=K123W2KZ8W70KB' https://test.[your.domain]/R2-ki.pdf --output abashiri.pdf
出力結果
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 4466k 100 4466k 0 0 5151k 0 --:--:-- --:--:-- --:--:-- 5151k
S3アップロードした4.4MBのPDFファイルをCloudFrontの署名付きCookieの制限付きでダウンロードできたことを確認できました。
$ ls -lh total 10392 -rw-r--r--@ 1 ohmura.yasutaka staff 4.4M 1 16 22:35 abashiri.pdf -rw-r--r-- 1 ohmura.yasutaka staff 122B 1 16 12:21 policy.json -rw-r--r-- 1 ohmura.yasutaka staff 1.6K 1 15 22:04 private_key.pem -rw-r--r-- 1 ohmura.yasutaka staff 451B 1 15 22:04 public_key.pem
Cookieなしでアクセスした場合はWEBブラウザでアクセスしたとき同様にMissingKey
のエラーでPDFファイルのダウンロードできませんでした。プライベートコンテンツとして正しく機能しています。
$ curl https://test.[your.domain]/R2-ki.pdf --output no-cookie-abashiri.pdf % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 146 100 146 0 0 784 0 --:--:-- --:--:-- --:--:-- 784 $ cat no-cookie-abashiri.pdf <?xml version="1.0" encoding="UTF-8"?><Error><Code>MissingKey</Code><Message>Missing Key-Pair-Id query parameter or cookie value</Message></Error>bash-
補足
カスタムポリシーの仕様
署名付きCookieでS3バケットの配下のa-folder
と、b-folder
アクセス可能で、c-folder
にアクセスはさせたくないといった場合を例に説明します。
private-bucket # S3バケット名 ├── a-folder # Aフォルダ │ ├── a1.pdf │ └── a2.jpg ├── b-folder # Bフォルダ │ └── b1.pdf └── c-folder # Cフォルダ ├── c1.pdf └── c2.pdf
カスタムポリシーのResource
は複数パス指定をサポートされていません。
以下、公式ドキュメントより
You can specify only one value for Resource.
Setting signed cookies using a custom policy - Amazon CloudFront
a-folder
と、b-folder
を署名付きCookieで許可したいからといって下記のようにResource
を複数書けないということです。
{ "Statement": [ { "Resource":"https://test.[your.domain]/a-folder/*", "Condition": { "DateLessThan": { "AWS:EpochTime":1610949489 } } }, { "Resource":"https://test.[your.domain]/b-folder/*", "Condition": { "DateLessThan": { "AWS:EpochTime":1610949489 } } } ] }
CookieのPath
指定で個々のフォルダに対する署名付きQookieを発行し使い分けするか、S3バケットのフォルダ構造を見直した方がよろしいかもしれません。カスタムポリシーの仕様を確認しご検討いただければと思います。
おわりに
アプリ書く人間ではないので具体的にどう実装するのかはイメージできないのですが、署名付きCookieでプライベートコンテンツを配信する手法については理解が深まりました。curl
の引数が余りにも見づらいので変数でスッキリさせたかったです。
変数に入れるまでは良かったのですが引数内でうまく展開できず断念しました。
$ POLICY=$(cat policy.json | openssl base64 | tr '+=/' '-_~') $ SIGNED_POLICY=$(cat policy.json | openssl sha1 -sign private_key.pem | openssl base64 | tr '+=/' '-_~') $ PUBKEY_ID='K123W2KZ8W70KB'
参考
CloudFront の署名付き Cookie によるプライベートコンテンツ配信でワイルドカードを使用する | Developers.IO